﻿using NCrontab;
using System;
using Loong.Domain.Entities.Auditing;
using Loong.Extensions;

namespace Loong.BackgroundJobs
{
    public class BackgroundJobInfo : CreationAuditedEntity<long>
    {
        public const int MaxJobTypeLength = 512;

        public const int MaxJobArgsLength = 1024 * 1024;

        public const int MaxCronLength = 128;

        public static int DefaultFirstWaitDuration = 60;

        public static double DefaultWaitFactor = 2.0;

        public virtual string JobType { get; set; }

        public virtual string JobArgs { get; set; }

        public virtual short TryCount { get; set; }

        public virtual string Cron { get; set; }

        public virtual DateTime NextTryTime { get; set; }

        public virtual DateTime? LastTryTime { get; set; }

        public virtual DateTime EndTryTime { get; set; }

        public virtual bool IsAbandoned { get; set; }

        public virtual BackgroundJobPriority Priority { get; set; }

        public virtual bool IsLocked { get; set; }

        public virtual DateTime? LockEndTime { get; set; }

        public BackgroundJobInfo()
        {
            NextTryTime = DateTime.Now;
            EndTryTime = DateTime.Now.AddDays(2);
            Priority = BackgroundJobPriority.Normal;
        }

        public virtual DateTime? CalculateNextTryTime()
        {
            var lastTryTime = LastTryTime.HasValue ? LastTryTime.Value : DateTime.Now;

            DateTime nextTryTime;

            if (Cron.IsNullOrEmpty())
            {
                var nextWaitDuration = DefaultFirstWaitDuration * (Math.Pow(DefaultWaitFactor, TryCount - 1));
                nextTryTime = lastTryTime.AddSeconds(nextWaitDuration);
            }
            else
            {
                nextTryTime = CrontabSchedule.Parse(Cron).GetNextOccurrence(lastTryTime);
            }

            if (nextTryTime > EndTryTime)
            {
                return null;
            }

            return nextTryTime;
        }
    }
}
